#include "mysql.hpp"
#include "user-odb.hxx"
#include "user.hxx"

/**
 * 封装对用户表（User表）的数据库操作。通过这个类，可以实现对用户表的增删改查（CRUD）操作，
 * 同时将数据库操作的细节（如事务管理、异常处理）封装在类内部，提供简洁的接口供外部调用。
 *
 * UserTable 类依赖于 User(user.hxx) 类，因为它的操作对象是 User 类的实例。

 * user.hxx 文件定义了用户的数据结构，并通过 ODB 映射到数据库表。
 * UserTable 类封装了对用户表的数据库操作，提供了插入、更新、查询等接口。
 * 两者共同完成了用户数据的定义和操作，是典型的 数据层 和 持久化层 的分离设计。
 */

namespace ken_im
{
class UserTable
{
  public:
    using ptr = std::shared_ptr<UserTable>;
    // 构造函数，接受一个odb::core::database的共享指针作为参数

    UserTable( const std::shared_ptr<odb::core::database> &db ) : _db( db )
    {
    }

    bool insert( const std::shared_ptr<User> &user )
    {
        try
        {
            odb::transaction trans( _db->begin() );
            _db->persist( *user );
            trans.commit();
        }
        catch ( std::exception &e )
        {
            LOG_ERROR( "新增用户失败 {}:{}！", user->nickname(), e.what() );
            return false;
        }
        return true;
    }

    bool update( const std::shared_ptr<User> &user )
    {
        try
        {
            odb::transaction trans( _db->begin() );
            _db->update( *user );
            trans.commit();
        }
        catch ( std::exception &e )
        {
            LOG_ERROR( "更新用户失败 {}:{}！", user->nickname(), e.what() );
            return false;
        }
        return true;
    }
    std::shared_ptr<User> select_by_nickname( const std::string &nickname )
    {
        std::shared_ptr<User> res;
        try
        {
            odb::transaction trans( _db->begin() );
            typedef odb::query<User> query;
            typedef odb::result<User> result;
            res.reset( _db->query_one<User>( query::nickname == nickname ) );
            trans.commit();
        }
        catch ( std::exception &e )
        {
            LOG_ERROR( "通过昵称查询用户失败 {}:{}！", nickname, e.what() );
        }
        return res;
    }
    std::shared_ptr<User> select_by_phone( const std::string &phone )
    {
        std::shared_ptr<User> res;
        try
        {
            odb::transaction trans( _db->begin() );
            typedef odb::query<User> query;
            typedef odb::result<User> result;
            res.reset( _db->query_one<User>( query::phone == phone ) );
            trans.commit();
        }
        catch ( std::exception &e )
        {
            LOG_ERROR( "通过手机号查询用户失败 {}:{}！", phone, e.what() );
        }
        return res;
    }
    std::shared_ptr<User> select_by_id( const std::string &user_id )
    {
        std::shared_ptr<User> res;
        try
        {
            odb::transaction trans( _db->begin() );
            typedef odb::query<User> query;
            typedef odb::result<User> result;
            res.reset( _db->query_one<User>( query::user_id == user_id ) );
            trans.commit();
        }
        catch ( std::exception &e )
        {
            LOG_ERROR( "通过用户ID查询用户失败 {}:{}！", user_id, e.what() );
        }
        return res;
    }
    std::vector<User>
    select_multi_users( const std::vector<std::string> &id_list )
    {
        // select * from user where id in ('id1', 'id2', ...)
        if ( id_list.empty() )
        {
            return std::vector<User>();
        }
        std::vector<User> res;
        try
        {
            odb::transaction trans( _db->begin() );
            typedef odb::query<User> query;
            typedef odb::result<User> result;
            std::stringstream ss;
            ss << "user_id in (";
            for ( const auto &id : id_list )
            {
                ss << "'" << id << "',";
            }
            std::string condition = ss.str();
            condition.pop_back();
            condition += ")";
            result r( _db->query<User>( condition ) );
            for ( result::iterator i( r.begin() ); i != r.end(); ++i )
            {
                res.push_back( *i );
            }
            trans.commit();
        }
        catch ( std::exception &e )
        {
            LOG_ERROR( "通过用户ID批量查询用户失败:{}！", e.what() );
        }
        return res;
    }

  private:
    std::shared_ptr<odb::core::database> _db;
};
} // namespace ken_im